﻿using System;
using System.Collections;
using System.Collections.Generic;
using Microsoft.Practices.Unity;
using NHibernate;
using NHibernate.Criterion;

namespace RG.Common.Provider
{
    public interface IDAOSession: IDisposable
    {
        IUnityContainer ParentCfg { get; set; }
        IList<T> List<T>(ICriterion expr);
        IList<T> List<T>(DetachedCriteria criteria);
        T Get<T>(object objId);
        IQuery GetNamedQuery(string queryName);

        // TODO переделать DAOTransaction на StatelessSession, тогда не надо будет Evict звать
        void Evict(object o);
        void Refresh(object o);
    }

    public interface IDAOTransaction : IDAOSession
    {
        /// <summary>
        /// Придется объявить устаревшим. 
        /// Так как во первых очень хочется перейти на StatelessSession
        /// а во вторых все равно нормально не работает добавление классов с Generator=assigned
        /// </summary>
        /// <param name="Obj"></param>
        void Put(object Obj);

        bool Contains(object obj);
        void Insert(object obj);
        void Update(object obj);
        void Delete(object obj);
        void Commit();
        void RollBack();
        void Flush();
    }

    public interface IDAOValidator
    {
        void Validate(object obj);
    }

    public interface IDAOProvider
    {
        String ConnectionString { get; }

        /// <summary>
        /// Вычищает оьъект с типом persistentObjType и идентификатором objId из кеша 2-го уровня
        /// Если objId == null - вычищает все объекты этого типа
        /// </summary>
        void Evict(Type persistentObjType, object objId);

        IDAOSession StartRead { get; }

        IDAOTransaction StartTransaction { get; }
    }

    public static class Provider_Extensions
    {
        public static void PutInTransaction(this IDAOProvider aProvider, object DBObj)
        {
            using (var tr = aProvider.StartTransaction)
            {
                tr.Put(DBObj);
                tr.Commit();
            }
        }

        
    }

    public static class IDAOSession_Resolve_Extension
    {
        public static T Resolve<T>(this IDAOSession from)
        {
            if (from.ParentCfg == null)
                throw new ApplicationException("DAOSession.ParentCfg is null");

            using (var cfg = from.ParentCfg.CreateChildContainer())
            {
                cfg.RegisterInstance(from, new ExternallyControlledLifetimeManager());
                return cfg.Resolve<T>();
            }
        }
    }

    public static class IUnityContainer_Resolve_Session_Extension
    {
        public static T Resolve<T>(this IUnityContainer cfg, IDAOSession from)
        {
            using (var childCfg = cfg.CreateChildContainer())
            {
                childCfg.RegisterInstance(from, new ExternallyControlledLifetimeManager());
                return childCfg.Resolve<T>();
            }
        }

        public static T Resolve<T>(this IUnityContainer cfg, IDAOSession from, String name)
        {
            using (var childCfg = cfg.CreateChildContainer())
            {
                childCfg.RegisterInstance(from, new ExternallyControlledLifetimeManager());
                return childCfg.Resolve<T>(name);
            }
        }

    }

}